﻿using System;
using System.Collections.Specialized;
using System.Linq;
using System.Linq.Expressions;
using System.Web.Mvc;
using System.Web.Routing;
using Inovout.Data.Domain;
using Inovout.Data.Repository;
using Inovout.Data.Service;

namespace Inovout.Web.Mvc
{
    /// <summary>
    /// 基于数据库操作的Controller基类
    /// 默认不允许匿名访问
    /// </summary>
    /// <typeparam name="TModel">模型类型</typeparam>
    public class RepositoryController<TModel> : BaseController where TModel : DataObject
    {
        public RepositoryController()
        {
            ViewData["ModelType"] = typeof(TModel);
        }
        private IRepositoryForControllerService<TModel> modelService;
        protected IRepositoryForControllerService<TModel> ModelService
        {
            get
            {
                if (modelService == null)
                {
                    modelService = base.GetService<IRepositoryForControllerService<TModel>>();
                }
                return modelService;
            }

        }


        protected override void Initialize(RequestContext requestContext)
        {
            base.Initialize(requestContext);
        }

        /// <summary>
        /// Action-默认
        /// </summary>
        /// <param name="queryCriteria">查询条件</param>
        /// <returns>ActionResult对象实例</returns>
        [Alias("所有")]
        public virtual ActionResult Index(QueryCriteria queryCriteria)
        {
            return View(Query(queryCriteria));
        }

        #region 创建&修改
        /// <summary>
        /// Action-新建
        /// </summary>
        /// <returns>ActionResult对象实例</returns>
        [HttpGet, Alias("创建")]
        public virtual ActionResult New()
        {
            return View(ModelService.New());
        }
        /// <summary>
        /// Action-保存新建模型
        /// </summary>
        /// <param name="model">模型对象实例</param>
        /// <returns>ActionResult对象实例</returns>
        [HttpPost, Alias("创建")]
        public virtual ActionResult New(TModel model)
        {
            if (ModelState.IsValid)
            {
                return Save(model);
            }
            return View(model);
        }
        /// <summary>
        /// Action-修改模型
        /// </summary>
        /// <returns>ActionResult对象实例</returns>
        [HttpGet, Alias("修改")]
        public virtual ActionResult Modify()
        {
            return View();
        }
        /// <summary>
        /// Action-保存修改的模型
        /// </summary>
        /// <param name="model">修改的模型对象实例</param>
        /// <returns>ActionResult对象实例</returns>
        [HttpPost, Alias("修改")]
        public virtual ActionResult Modify(TModel model)
        {
            if (ModelState.IsValid)
            {
                return Save(model);
            }
            return View(model);
        }

        /// <summary>
        /// Action-编辑模型对象
        /// </summary>
        /// <param name="model">模型对象实例</param>
        /// <returns>ActionResult对象实例</returns>
        [Alias("编辑")]
        public virtual ActionResult Edit(TModel model)
        {
            if (ModelState.IsValid && this.Request.HttpMethod.ToLower().Equals("post"))
            {
                return Save(model);
            }
            return View(model);
        }
        /// <summary>
        /// Action-删除模型对象
        /// </summary>
        /// <param name="model">模型对象实例</param>
        /// <returns>ActionResult对象实例</returns>
        public virtual ActionResult Delete(TModel model)
        {

            ModelService.Delete(model);
            return RedirectToReturnUrl();

        }
        /// <summary>
        /// Action-保存模型对象
        /// </summary>
        /// <param name="model">模型对象实例</param>
        /// <returns>ActionResult对象实例</returns>
        [HttpPost]
        public virtual ActionResult Save(TModel model)
        {
            if (ModelState.IsValid && this.Request.HttpMethod.ToLower().Equals("post"))
            {
                ModelService.Save(model);
            }
            return RedirectToReturnUrl();
        }

        #endregion

        #region 查询
        /// <summary>
        /// Action-列出符合查询条件的模型对象集合
        /// </summary>
        /// <param name="queryCriteria">查询条件规则对象</param>
        /// <param name="ps">每页显示条数</param>
        /// <param name="pi">需显示的第几页</param>
        /// <returns>ActionResult对象实例</returns>
        public virtual ActionResult List([ModelBinder(typeof(QueryCriteriaModelBinder))] QueryCriteria queryCriteria, int? ps = 20, int? pi = 1)
        {
            return View(this.Query(queryCriteria, ps, pi));
        }

        /// <summary>
        /// 查询符合条件规则的模型对偶集合
        /// </summary>
        /// <param name="queryCriteria">查询条件规则对象</param>
        /// <param name="ps">每页显示条数</param>
        /// <param name="pi">需显示的第几页</param>
        /// <returns>ActionResult对象实例</returns>
        protected IDataObjectPagedSet<TModel> Query(QueryCriteria queryCriteria, int? ps = null, int? pi = null)
        {
            queryCriteria.ModelType = typeof(TModel);

            var result =PagedQuery(ModelService.Query(queryCriteria));

            ViewData.SetFilterCriterias(queryCriteria.Filters, result);
            ViewData.SetOrderCriterias(queryCriteria.Orders.ToArray(), result);
            //ViewData[QueryCriteriaHelper.DefaultQueryCriterionsKey] = queryCriteria;

            return result;
        }

        protected IDataObjectPagedSet<TModel> PagedQuery(IQueryable<TModel> queryable, int? ps = null, int? pi = null)
        {
            if (!ps.HasValue)
            {
                var psResult = this.ValueProvider.GetValue("ps");
                if (psResult == null)
                {
                    ps = 20;
                }
                else
                {
                    ps = int.Parse(psResult.AttemptedValue);
                }
            }

            if (this.Request.HttpMethod.Equals("post", StringComparison.CurrentCultureIgnoreCase))
            {
                //如果POST，表示通过查询提交，统一设置为显示第1页。
                pi = 1;
            }
            else if (!pi.HasValue)
            {
                var piResult = this.ValueProvider.GetValue("pi");
                if (piResult == null)
                {
                    pi = 1;
                }
                else
                {
                    pi = int.Parse(piResult.AttemptedValue);
                }
            }

            var result = queryable.ToPagedSet(ps.Value, pi.Value);

              return result;
        }

        private QueryCriteriaBuilder<TModel> queryCriteriaBuilder;
        /// <summary>
        /// 查询条件规则生成器
        /// </summary>
        protected QueryCriteriaBuilder<TModel> QueryCriteriaBuilder
        {
            get
            {
                if (queryCriteriaBuilder == null)
                {
                    queryCriteriaBuilder = new QueryCriteriaBuilder<TModel>();
                }
                return queryCriteriaBuilder;
            }
        }

        private FilterCriteriaColllectionBuilder<TModel> filterCriteriaCollectionBuilder;
        /// <summary>
        /// 查询条件过滤器规则生成器
        /// </summary>
        protected FilterCriteriaColllectionBuilder<TModel> FilterCriteriaColllectionBuilder
        {
            get
            {
                if (filterCriteriaCollectionBuilder == null)
                {
                    filterCriteriaCollectionBuilder = new FilterCriteriaColllectionBuilder<TModel>();
                }
                return filterCriteriaCollectionBuilder;
            }
        }

        private OrderCriteriaColllectionBuilder<TModel> orderCriteriaCollectionBuilder;
        /// <summary>
        /// 查询排序规则生成器
        /// </summary>
        protected OrderCriteriaColllectionBuilder<TModel> OrderCriteriaColllectionBuilder
        {
            get
            {
                if (orderCriteriaCollectionBuilder == null)
                {
                    orderCriteriaCollectionBuilder = new OrderCriteriaColllectionBuilder<TModel>();
                }
                return orderCriteriaCollectionBuilder;
            }
        }

        #region View-QueryCriteria
        /// <summary>
        /// View-自动查询符合条件的模型对象集合，并返回相应的View视图
        /// </summary>
        /// <param name="queryCriteria">查询条件规则对象</param>
        /// <returns>ViewResult对象实例</returns>
        protected internal ViewResult View(QueryCriteria queryCriteria)
        {
            return View(null, null, queryCriteria);
        }
        /// <summary>
        /// View-自动查询符合条件的模型对象集合，并返回相应的View视图
        /// </summary>
        /// <param name="viewName">视图名称</param>
        /// <param name="queryCriteria">查询条件规则对象</param>
        /// <returns>ViewResult对象实例</returns>
        protected internal ViewResult View(string viewName, QueryCriteria queryCriteria)
        {
            return View(viewName, null, queryCriteria);
        }
        /// <summary>
        /// View-自动查询符合条件的模型对象集合，并返回相应的View视图
        /// </summary>
        /// <param name="viewName">视图名称</param>
        /// <param name="masterName">母板视图名称</param>
        /// <param name="queryCriteria">查询条件规则对象</param>
        /// <returns>ViewResult对象实例</returns>
        protected internal virtual ViewResult View(string viewName, string masterName, QueryCriteria queryCriteria)
        {
            return base.View(viewName, masterName, Query(queryCriteria));
        }
        /// <summary>
        /// View-自动查询符合条件的模型对象集合，并返回相应的View视图
        /// </summary>
        /// <param name="view">视图对象实例</param>
        /// <param name="queryCriteria">查询条件规则对象</param>
        /// <returns>ViewResult对象实例</returns>
        protected internal virtual ViewResult View(IView view, QueryCriteria queryCriteria)
        {

            return base.View(view, Query(queryCriteria));
        }
        #endregion

        #region View-QueryCriteriaBuilder
        /// <summary>
        /// View-自动查询符合通过查询条件生成品构建的条件的模型对象集合，并返回相应的View视图
        /// </summary>
        /// <param name="queryCriteriaBuilder">查询条件规则生成器</param>
        /// <returns>ViewResult对象实例</returns>
        protected internal ViewResult View(QueryCriteriaBuilder<TModel> queryCriteriaBuilder)
        {
            return View(null, null, queryCriteriaBuilder);
        }
        /// <summary>
        /// View-自动查询符合通过查询条件生成品构建的条件的模型对象集合，并返回相应的View视图
        /// </summary>
        /// <param name="viewName">视图名称</param>
        /// <param name="queryCriteriaBuilder">查询条件规则生成器</param>
        /// <returns>ViewResult对象实例</returns>
        protected internal ViewResult View(string viewName, QueryCriteriaBuilder<TModel> queryCriteriaBuilder)
        {
            return View(viewName, null, queryCriteriaBuilder);
        }
        /// <summary>
        /// View-自动查询符合通过查询条件生成品构建的条件的模型对象集合，并返回相应的View视图
        /// </summary>
        /// <param name="viewName">视图名称</param>
        /// <param name="masterName">母板视图名称</param>
        /// <param name="queryCriteriaBuilder">查询条件规则生成器</param>
        /// <returns>ViewResult对象实例</returns>
        protected internal virtual ViewResult View(string viewName, string masterName, QueryCriteriaBuilder<TModel> queryCriteriaBuilder)
        {
            return base.View(viewName, masterName, Query(queryCriteriaBuilder.QueryCriteria));
        }
        /// <summary>
        /// View-自动查询符合通过查询条件生成品构建的条件的模型对象集合，并返回相应的View视图
        /// </summary>
        /// <param name="view">视图对象实例</param>
        /// <param name="queryCriteriaBuilder">查询条件规则生成器</param>
        /// <returns>ViewResult对象实例</returns>
        protected internal virtual ViewResult View(IView view, QueryCriteriaBuilder<TModel> queryCriteriaBuilder)
        {
            return base.View(view, Query(queryCriteriaBuilder.QueryCriteria));
        }
        #endregion
        #endregion

        /// <summary>
        /// 验证模型
        /// </summary>
        /// <param name="model">模型对象实例</param>
        /// <returns>JsonResult对象实例</returns>
        [AllowAnonymous]
        public virtual JsonResult Validate(TModel model)
        {

            DataObjectTypeDescriptor dataObjectTypeDescriptor = DataObjectTypeDescriptor.Get<TModel>();
            NameValueCollection propertyDictionary = base.HttpContext.Request.HttpMethod.ToLower().Equals("get")
               ? base.HttpContext.Request.QueryString
               : base.HttpContext.Request.Form;
            //只会剩下一个。
            DataObjectPropertyDescriptor dataObjectPropertyDescriptor = dataObjectTypeDescriptor.Properties.Single(
                    p => propertyDictionary.AllKeys.Contains(p.Name) && !p.Name.Equals(dataObjectTypeDescriptor.IdentifierProperty.Name)
                ) as DataObjectPropertyDescriptor;

            if (this.ModelState.IsValidField(dataObjectPropertyDescriptor.Name))
            {
                return Json(true, JsonRequestBehavior.AllowGet);
            }
            else
            {
                var validationResult = this.ModelState.First(ms => ms.Key.StartsWith(dataObjectPropertyDescriptor.Name) && ms.Value.Errors.Any()).Value.Errors.First();
                return Json(validationResult.ErrorMessage, JsonRequestBehavior.AllowGet);
            }
        }

        /// <summary>
        /// 为属性增加数据源
        /// </summary>
        /// <typeparam name="TProperty">属性类型</typeparam>
        /// <typeparam name="TSource">数据源类型</typeparam>
        /// <param name="propertyAccessor">数据源表达式</param>
        /// <param name="func"></param>
        public void AddDataSource<TProperty, TSource>(Expression<Func<TModel, TProperty>> propertyAccessor, Func<TSource> func)
        {
            this.ViewData.AddDataSource(ExpressionHelper.GetExpressionText(propertyAccessor), func);
        }
        protected void AddError<TProperty>(Expression<Func<TModel, TProperty>> propertyAccessor, string errorMessage)
        {
            this.ModelState.AddModelError(ExpressionHelper.GetExpressionText(propertyAccessor), errorMessage);
            this.GetService<TransactionTracker>().ExceptionContext.Exceptions = new Exception[] { new ArgumentException(errorMessage) };

        }
    }
}